#pragma once

#include "AttrPartProxy.h"

class Attribute
{
public:
	class Loader {
	public:
		virtual void LoadBase(double attrs[]) = 0;
		virtual void LoadBody(AttrPartProxy& proxy) = 0;
		virtual void LoadEquip(AttrPartProxy& proxy) = 0;
		virtual void LoadExtraAttrs() = 0;
	};

	Attribute(Unit* pOwner);
	~Attribute();

	void Reload(uint32 flags = (u32)ATTRPARTTYPE::ALL);
	void FlushAttrValue();

	void ModAttr(ATTRARITHTYPE arith, ATTRPARTTYPE part, ATTRTYPE type, double value);
	void ModXAttr( ATTRPARTTYPE part, uint32 type, double value);
	double GetAttr(ATTRTYPE type) const;

	void SetAttrEx(ATTREXTYPE type, double value);
	void ModAttrEx(ATTREXTYPE type, double value);
	double GetAttrEx(ATTREXTYPE type) const;

	void AttachAttrVex(ATTRVEXTYPE type, double value);
	void DetachAttrVex(ATTRVEXTYPE type, double value);
	const std::vector<double>& GetAttrVex(ATTRVEXTYPE type) const;

	void AttachAttrSex(ATTRSEXTYPE type, LuaRef&& value);
	void DetachAttrSex(ATTRSEXTYPE type, LuaRef&& value);
	const std::vector<LuaRef>& GetAttrSex(ATTRSEXTYPE type) const;

	double GetHitChance(Unit* pTarget) const;
	double GetCritiHitChance(Unit* pTarget) const;
	double GetCritiHitIntensity(Unit* pTarget) const;

	double CalcAttackDamage(Unit* pVictim, double attackRate, double attackValue);

	const double(&GetAttrCacheValue()const)[(int)ATTRTYPE::COUNT] { return m_attrCacheValue; }
	bool IsAttrDirty() const { return m_isAttrDirty; }

	AttrPartProxy& GetAttrPartProxy(ATTRPARTTYPE part) { return m_attrPartProxies[(int)part]; }

private:
	void ReloadPart(ATTRPARTTYPE type);
	void ReloadBase();
	void ReloadBody();
	void ReloadEquip();

	double SumAttrValue(ATTRARITHTYPE arith, ATTRTYPE type, double initValue) const;
	double CalcAttrValue(ATTRTYPE type) const;

	Unit* const m_pOwner;
	double m_attr[(int)ATTRARITHTYPE::COUNT][(int)ATTRPARTTYPE::COUNT][(int)ATTRTYPE::COUNT];
	double m_attrEx[(int)ATTREXTYPE::COUNT];
	std::vector<double> m_attrVex[(int)ATTRVEXTYPE::COUNT];
	std::vector<LuaRef> m_attrSex[(int)ATTRSEXTYPE::COUNT];

	double m_attrCacheValue[(int)ATTRTYPE::COUNT];
	bool m_isAttrDirty;

	AttrPartProxy m_attrPartProxies[(int)ATTRPARTTYPE::COUNT];
};
